#pragma once

#include <vector>
#include <iostream>
#include "Sem.hpp"
#include "Mutex.hpp"

static const int gcap = 5;
using namespace SemModule;
using namespace MutexModule;

template <typename T>
class RingQueue
{
public:
    RingQueue(int cap = gcap)
        : _cap(cap)
        , _rq(cap)
        , _blank_sem(cap)
        , _data_sem(0)
        , _p_step(0)
        , _c_step(0)
    {
    }

    //信号量无需判断资源有否，因为信号量就是记录资源的，就是专业干这个的
    // 入队列
    void Equeue(const T &in)
    {
        // 生产者访问
        _pmutex.Lock();
        //申请信号量，空位置信号量
        _blank_sem.P();
        //生产
        _rq[_p_step] = in;
        //更新下标
        ++_p_step;
        //维持环形特性
        _p_step %= _cap;
        //让消费者进行V操作
        _data_sem.V();

        _pmutex.Unlock();

    }

    // 出队列
    void Pop(T *out)
    {
        // 消费者访问
        _cmutex.Lock();
        //申请信号量
        _data_sem.P();
        //消费
        *out = _rq[_c_step];
        //更新下标
        ++_c_step;
        _c_step %= _cap;
        _blank_sem.V();

        _cmutex.Unlock();
    }

    ~RingQueue()
    {
    }

private:
    std::vector<T> _rq; // 环形队列
    int _cap;
    // 生产者关注空格子
    Sem _blank_sem; // 空格子
    int _p_step;   // 生产者下标
    // 消费者关注数据数量
    Sem _data_sem; // 数据数量
    int _c_step;   // 消费者下标

    //维护多生产，多消费的锁,而且要两把锁
    Mutex _cmutex;
    Mutex _pmutex;


};